-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Open the help in the down area (pager) #7713
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
So, I think this PR should be ready for a first round of reviews. As a quick summary, it brings back the behavior of the pager just like the classic notebook. This has been missing since the early Jupyter Notebook 7 releases (released a bit more than two years ago), and there's been some feedback that this was still missing. I've also added some UI tests to cover some cases, and also added a new page in the docs so that folks can opt out of this new behavior and return to the JupyterLab behavior if they want to. If folks would like to try it, that would be great, let me know what you think. I'm also happy to iterate on a different approach if you think the current one could be improved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a pager widget that displays help documentation in the down area (inspector panel) similar to classic notebook behavior, providing an alternative to JupyterLab's inline output approach. Users can toggle this behavior through settings to maintain compatibility with either classic notebook or JupyterLab workflows.
- Implements a new pager plugin that intercepts kernel messages with pager payloads and displays them in the inspector panel
- Adds configuration option to switch between down-area display and inline cell output behavior
- Updates shell layout to support inspector placement in the down area
Reviewed Changes
Copilot reviewed 9 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
File | Description |
---|---|
packages/notebook-extension/src/index.ts | Core pager plugin implementation with kernel message handling and inspector integration |
packages/notebook-extension/schema/pager.json | Settings schema for configuring pager behavior |
packages/notebook-extension/package.json | Added inspector dependency |
packages/application/src/shell.ts | Enhanced down panel activation to support tab switching |
packages/application-extension/schema/shell.json | Updated shell configuration to place Inspector in down area by default |
ui-tests/test/notebook.spec.ts | Added test to verify pager opens in down area with question mark syntax |
docs/source/user-documentation.md | Added pager documentation reference |
docs/source/pager.md | Complete user documentation for pager functionality |
app/package.json | Added inspector extension dependencies and configuration |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Co-authored-by: Copilot <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this contribution @jtpio, it's a nice addition to the Notebook UI, especially for users used to Nbclassic. Please find some comments and suggestions below.
|
||
// Listen for parent disposal. | ||
panel.disposed.connect(() => { | ||
inspectionHandler.dispose(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All inspection handlers would not be properly disposed of because inspectionHandler
is a global variable (L901) and each panel.disposed.connect()
callback (L967-969) references this global variable, not the specific handler instance created for that panel. So when notebooks are closed only the most recently created handler gets disposed while previous handlers remain in memory with associated resources not being freed.
Test by opening multiple notebooks then closing any other than last created notebook, note that only last handler gets disposed of.
Tracking handlers per panel and ensuring correct disposal of all handlers would fix this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering is this is a real issue in practice.
In Jupyter Notebook there is only one notebook at a time on the page, which actually should never really be disposed. So there should be one inspection handler instantiated on the page.
This code snippet was inspired by the upstream implementation in JupyterLab, but it could be cleaned up or simplified a bit to only handle the Notebook use case.
app.shell.currentChanged?.connect((_, args) => setSource(args.newValue)); | ||
void app.restored.then(() => setSource(app.shell.currentWidget)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setSource()
can be called before inspectionHandler
is initialized (L932), for example during app startup, causing undefined access when app.shell
events fire before any notebook is opened.
To test, add logging inspectionHandler
at L975, launch notebook server without opening any notebooks, refresh the browser page while monitoring the logs, see inspectionHandler
is undefined.
While this doesn't break functionality (opening a notebook later initializes the handler), it puts the inspector in an invalid state during startup and could cause issues if other components try to use it during that window.
Adding a null check to setSource()
or declaring inspectionHandler
as nullable and initializing it to null would fix this.
(item) => item.source !== 'page' | ||
); | ||
if (content.payload.length === 0) { | ||
// If no other payloads remain, delete the payload array from the content. | ||
delete content.payload; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mutates kernel messages, other extensions / components would receive the modified version missing pager payloads. Based on my research JupyterLab's codebase as of now does not mutate kernel messages in other places. For example, @jupyterlab/outputarea
copies the message.
Would it be possible to accomplish the same without mutating the kernel messages? For example watch cell output model changes to detect pager payloads during cell execution and route them to the down area before normal output rendering?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, maybe there is a way to check the outputs directly.
Need to check if this will have any visual side-effect too (for example the output is rendered and then removed).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example, @jupyterlab/outputarea copies the message.
I looked a bit more into this. While we could set up handlers to check the output area model, information about the message gets lost when it's added to the output:
const output: nbformat.IOutput = {
output_type: 'display_data',
data: (page as any).data as nbformat.IMimeBundle,
metadata: {}
};
model.add(output);
And there doesn't seem to be any easy way to know if an output is the result of pager information.

Fixes #6692
Fixes #1135
To offer a behavior similar to the classic notebook:
notebook-down-pager.mp4
The idea would be to have this behavior by default in Notebook 7.5, with a setting to disable it and have the pager data be displayed in the cell output like in JupyterLab:
notebook-pager-disabled.mp4
Example with
xeus-cpp
showing atext/html
bundle:notebook-xeus-cpp-pager.mp4